package com.vs.dao.base;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import com.vs.util.GenericsUtil;




/**
 * DAO层封装使用了泛型，包含常用的CURD和分页操作
 */
@SuppressWarnings("unchecked")
public abstract class AbstractBaseDao<T> extends HibernateDaoSupport {
	protected Class<T> entityClass = GenericsUtil.getSuperClassGenricType(this.getClass());
	protected String entityClassName = getEntityName(this.entityClass);
	protected String keyFieldName = getKeyFieldName(this.entityClass);

	private static Log log = LogFactory.getLog(AbstractBaseDao.class);

	// 为父类HibernateDaoSupport注入sessionFactory的值
	public void setSuperSessionFactory(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}

	/**
	 * 多条件查询
	 */
	public List findByPropertys(final String wherejpql, final Object[] queryParams) {
		return findByPropertys(-1, -1, wherejpql, queryParams, null);
	}

	/**
	 * 多条件带排序查询
	 */
	public List findByPropertys(final String wherejpql, final Object[] queryParams, 
			final Map<String, String> orderby) {
		return findByPropertys(-1, -1, wherejpql, queryParams, orderby);
	}

	/**
	 * 根据类属性分页查询
	 * @param firstIndex
	 * @param maxResult
	 * @param whereClause
	 * @param queryParams
	 * @param orderByMap
	 * @return
	 */
	public List findByPropertys(final int firstIndex, final int maxResult, final String whereClause,
								final Object[] queryParams,	final Map<String, String> orderByMap) {
		return (List) super.getHibernateTemplate().execute(new HibernateCallback<T>() {
			public T doInHibernate(Session session)
					throws HibernateException, SQLException {
				String hql = "from " + entityClassName + " o "
						+ (whereClause == null || "".equals(whereClause.trim()) ? "" : " where " + whereClause)
						+ buildOrderByClause(orderByMap);
				Query query = session.createQuery(hql);
				setQueryParams(query, queryParams);// where
				if (firstIndex != -1 && maxResult != -1)
					query.setFirstResult(firstIndex).setMaxResults(maxResult);
				System.out.println("后台打印HQL:" + hql);
				return (T) query.list();
			}
		});
	}
	
	/**
	 * 分组查询总条数
	 * @param hql
	 * @return
	 */
	public List findByGroupCount(final String whereClause, final Object[] queryParams){
		return (List) super.getHibernateTemplate().execute(new HibernateCallback<T>() {
			public T doInHibernate(Session session) throws HibernateException, SQLException {
				String hql = "select count(*) from " + entityClassName + " o "
							+ (whereClause == null || "".equals(whereClause.trim()) ? "" : " where " + whereClause)
							+ " group by o.indexstr";
				Query query = session.createQuery(hql);
				setQueryParams(query,queryParams);
				return (T) query.list();
			}
		});
	}
	
	/**
	 * 分组分页查询
	 * @param hql
	 * @return
	 */
	public List findByGroupAndPage(final int firstindex, final int maxresult, final String sql) {
		return getHibernateTemplate().executeFind(new HibernateCallback<T>() {
			public T doInHibernate(Session session) throws HibernateException, SQLException {
				Query query = session.createSQLQuery(sql);
				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult(firstindex).setMaxResults(maxresult);
				return (T) query.list();
			}
		});
	}

	/**
	 * 原生SQL查询
	 * @param sql 原生SQL查询语句
	 * @return SQL查询结果
	 */
	public List findBySQL(final String sql) {
		return getHibernateTemplate().executeFind(new HibernateCallback<T>() {
			public T doInHibernate(Session session) throws HibernateException, SQLException {
				return (T) session.createSQLQuery(sql).list();
			}
		});
	}

	/**
	 * 根据实体某个属性等于某值查询
	 * @param propertyName 属性名
	 * @param value 属性值
	 * @return 指定属性等于属性值的实体集合
	 */
	public List<T> findByProperty(String propertyName, Object value) {
		String queryString = "from " + entityClassName + " o where o." + propertyName + "= ?";
		return super.getHibernateTemplate().find(queryString, value);
	}

	/**
	 * 根据实体某个属性进行匹配(like)查询
	 * @param propertyName 属性名
	 * @param value 属性值
	 * @return 满足条件的实体集合
	 */
	public List<T> findEntityListByLike(String propertyName, Object value) {
		String queryString = "from " + entityClassName + " o where o." + propertyName + " like ?";
		return super.getHibernateTemplate().find(queryString, "%" + value + "%");
	}

	public List findByPropertyOrderByStrAndRownum(String propertyName, final Object value, 
			Object sortValue, Object sortDesc, final Integer rownum) {
		final String queryString = "from " + entityClassName + " o where o."
				+ propertyName + "= ? order by o." + sortValue + " " + sortDesc;
		try {
			if (rownum != null && rownum > 0) {
				return getHibernateTemplate().executeFind(new HibernateCallback<T>() {
					public T doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(queryString);
						query.setParameter(0, value);
						query.setMaxResults(rownum);
						return (T) query.list();
					}
				});
			} else
				return getHibernateTemplate().find(queryString, "%" + value + "%");
		} catch (RuntimeException re) {
			log.error("find " + queryString, re);
			throw re;
		}
	}

	/**
	 * 根据hql查询,直接使用HibernateTemplate的find函数. 取有限条数
	 */
	public List findByPropertyOrderByAndRownum(String propertyName, final Object value,
												Object sortValue, final Integer rownum) {
		return findByPropertyOrderByStrAndRownum(propertyName, value, sortValue, null, rownum);
	}

	/**
	 * 根据hql查询,直接使用HibernateTemplate的find函数.
	 * 
	 * @param hql
	 * @param rownum:
	 *            取有限条数
	 * @param values
	 * @return
	 */
	public List find(final String hql, final Integer rownum) {
		try {
			if (rownum != null && rownum > 0) {
				return getHibernateTemplate().executeFind(
						new HibernateCallback<T>() {
							public T doInHibernate(Session session)
									throws HibernateException, SQLException {
								Query query = session.createQuery(hql);
								query.setMaxResults(rownum);
								return (T) query.list();
							}
						});
			} else if( rownum == -1999){
				return getHibernateTemplate().executeFind(
						new HibernateCallback() {
							public Object  doInHibernate(Session session)
									throws HibernateException, SQLException {
								Query query = session.createSQLQuery(hql);
								return  query.list();
							}
						});

			}else if( rownum == -1998){
				return getHibernateTemplate().executeFind(
						new HibernateCallback() {
							public Object  doInHibernate(Session session)
									throws HibernateException, SQLException {
								Query query = session.createSQLQuery(hql);
								int i=query.executeUpdate();List list=new ArrayList();list.add(i);
								return  list;
							}
						});

			}else
			return getHibernateTemplate().find(hql);
		} catch (RuntimeException re) {
			log.error("find " + hql, re);
			throw re;
		}
	}


	/**
	 * 查询某个类的list
	 * @return
	 */
	public List<T> findEntityList() {
		return getHibernateTemplate().executeFind(new HibernateCallback<T>() {
			public T doInHibernate(Session session) throws HibernateException, SQLException {
				String hql = "from " + entityClassName + " ";
				Query query = session.createQuery(hql);
				return (T) query.list();
			}
		});
	}

	/**
	 * 根据属性名和属性值查询唯一对象.!!!
	 * @return 符合条件的唯一对象 or null if not found.
	 */
	public <T> T findUniqueBy(String propertyName, Object value) {
		T t = null;
		try {
			Assert.hasText(propertyName);
			t = (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return t;
	}

	private <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
		Criteria criteria = null;
		try {
			criteria = getSession().createCriteria(entityClass);
			for (Criterion c : criterions) {
				criteria.add(c);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return criteria;
	}

	/**
	 * 创建Query对象.
	 * 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
	 * 留意可以连续设置,如下：
	 * <pre>
	 * dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
	 * </pre>
	 * 调用方式如下：
	 * <pre>
	 *          dao.createQuery(hql)
	 *          dao.createQuery(hql,arg0);
	 *          dao.createQuery(hql,arg0,arg1);
	 *          dao.createQuery(hql,new Object[arg0,arg1,arg2])
	 * </pre>
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {
		Query query = null;
		try {
			Assert.hasText(hql);
			query = getSession().createQuery(hql);
			if (values != null) {
				for (int i = 0; i < values.length; i++) {
					query.setParameter(i, values[i]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return query;
	}

	/**
	 * flush
	 */
	public void flush() {
		try {
			getHibernateTemplate().flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * clear
	 */
	public void clear() {
		try {
			getHibernateTemplate().clear();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 删除指定对象.
	 * @param o 要删除的对象
	 */
	public void remove(Object o) {
		try {
			//super.getHibernateTemplate().getSessionFactory().getCurrentSession().setFlushMode(FlushMode.AUTO);
			getHibernateTemplate().delete(o);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void delete(Serializable... entityids) {
		for (Object id : entityids) {
			remove(find((Serializable) id));
		}
	}

	public T find(Serializable entityId) {
		if (null != entityId)
			return (T) super.getHibernateTemplate().get(entityClass, entityId);
		return null;
	}

	/**
	 * 获取全部对象.
	 */
	public <T> List<T> getAll() {
		List<T> list = null;
		try {
			list = (List<T>) getHibernateTemplate().loadAll(entityClass);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * 获取全部对象,带排序字段与升降序参数.
	 */
	public <T> List<T> getAll(String orderBy, boolean isAsc) {
		List<T> list = null;
		try {
			Assert.hasText(orderBy);
			if (isAsc) {
				list = getHibernateTemplate().findByCriteria(
						DetachedCriteria.forClass(entityClass).addOrder(
								Order.asc(orderBy)));
			} else {
				list = getHibernateTemplate().findByCriteria(
						DetachedCriteria.forClass(entityClass).addOrder(
								Order.desc(orderBy)));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	public <T> T merge() {
		T t = null;
		log.debug("merging " + entityClass.getClass().getName() + " instance");
		try {
			t = (T) getHibernateTemplate().merge(entityClass);
			log.debug("merge successful");
		} catch (Exception e) {
			log.error("merge failed", e);
			e.printStackTrace();
		}
		return t;
	}

	/**
	 * 获取记录总数
	 * @param 记录总数
	 */
	public int getCount() {
		String hql = "select count( " + keyFieldName + ") from " + entityClassName;
		return Integer.parseInt(super.getHibernateTemplate().find(hql).get(0).toString());
	}
	
	/**
	 * 获取满足指定条件的记录总数
	 * @return 满足条件的记录数
	 */
	public int getCount(String whereSQL,Object [] params) {
		String hql = "select count(" + keyFieldName + ") from " + entityClassName + " o where";
		if (!StringUtils.isEmpty(whereSQL)) {
			hql += whereSQL;
			return Integer.parseInt(getHibernateTemplate().find(hql, params).get(0).toString());
		}
		return Integer.parseInt(getHibernateTemplate().find(hql).get(0).toString());
	}

	/**
	 * 保存实体对象
	 * @param entity 要保存的实体对象
	 */
	public void save(Object entity) {
		try {
			super.getHibernateTemplate().save(entity);
			//super.getHibernateTemplate().flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 更新实体对象
	 * @param entity 要更新的实体对象
	 */
	public void update(Object entity) {
		try {
			//super.getHibernateTemplate().getSessionFactory().getCurrentSession().setFlushMode(FlushMode.AUTO);
			//super.getHibernateTemplate().setFlushMode(2);
			super.getHibernateTemplate().update(entity);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void saveOrUpdate(Object entity) {
		try {
			getHibernateTemplate().saveOrUpdate(entity);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取实体的名称
	 * @param <E>
	 * @param clazz 实体类
	 * @return
	 */
	public static <T> String getEntityName(Class<T> clazz) {
		String entityname = clazz.getSimpleName();
		Entity entity = clazz.getAnnotation(Entity.class);
		if (entity != null && entity.name() != null && !"".equals(entity.name())) {
			entityname = entity.name();
		}
		return entityname;
	}

	/**
	 * 获取实体的主键
	 * @param <E>
	 * @param clazz 实体类
	 * @return 主键名
	 */
	public static <E> String getKeyFieldName(Class<E> clazz) {
		try {
			PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
			for (PropertyDescriptor propertydesc : propertyDescriptors) {
				Method method = propertydesc.getReadMethod();
				if (null != method && null != method.getAnnotation(javax.persistence.Id.class)) {
					return propertydesc.getName();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "id";
	}

	/**
	 * 设置HQL里边的属性值
	 * @param query
	 * @param queryParams
	 */
	public static void setQueryParams(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i, queryParams[i]);// 从0开始
			}
		}
	}

	/**
	 * 组装order by语句
	 * @param orderby
	 * @return
	 */
	public static String buildOrderByClause(Map<String, String> orderby) {
		StringBuffer orderByClause = new StringBuffer("");
		if (orderby != null && orderby.size() > 0) {
			orderByClause.append(" order by ");
			for (String key : orderby.keySet()) {
				orderByClause.append("o.").append(key).append(" ").append(orderby.get(key)).append(",");
			}
			orderByClause.deleteCharAt(orderByClause.length() - 1);
		}
		return orderByClause.toString();
	}

	/**
	 * 获取字段数
	 * @param <E>
	 * @param clazz
	 * @return
	 */
	public static <E> String getCountField(Class<E> clazz) {
		String out = "o";
		try {
			PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
			for (PropertyDescriptor propertydesc : propertyDescriptors) {
				Method method = propertydesc.getReadMethod();
				if (method != null && method.isAnnotationPresent(EmbeddedId.class)) {
					PropertyDescriptor[] ps = Introspector.getBeanInfo(propertydesc.getPropertyType()).getPropertyDescriptors();
					out = "o." + propertydesc.getName() + "." + (!ps[1].getName().equals("class") ? ps[1].getName() : ps[0].getName());
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return out;
	}

	public List<T> findByPropertyOrderBy(String propertyName, Object id, Object sortValue) {
		String queryString = "from " + entityClassName + " o where o."
				+ propertyName + "= ? order by o." + sortValue;
		return super.getHibernateTemplate().find(queryString, id);
	}
}
